package com.team2.shoppingService;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;


import com.team2.imageComparison.CyberImageMatcher;
import com.team2.shared.CyberException;
import com.team2.shared.ServerProduct;
import com.team2.shared.ServerStore;
import com.team2.shared.SharedConstants;



public class Shopper {
	private static CyberImageMatcher imageMatcher = new CyberImageMatcher();
	
	public static String searchFromBarcode(String barcode) throws CyberException{
		String title=null;
		String xmlString = new WebHarvest().GetProductCatalog(barcode, Configuration.getBarcodeConfigFile());
		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
		DocumentBuilder builder;  
		try  
		{  
			builder = factory.newDocumentBuilder();  
			Document document = builder.parse( new InputSource( new StringReader( xmlString ) ) );  
			org.w3c.dom.NodeList nodeList = document.getElementsByTagName("title");

			if(nodeList != null && nodeList.getLength() > 0) {
				for(int i=0;i<nodeList.getLength();i++){
					Node tempNode=nodeList.item(i).getFirstChild();
						if (tempNode!=null){
							title = tempNode.getNodeValue();
							title = title.trim();
							//System.out.println("potential:"+title);
							if(title.length()<=10||title.contains(barcode)) continue;
							break;
						}
				}
			}
			
		} catch (Exception e) {  
			e.printStackTrace();  
		} 
		if(title==null){
			throw new CyberException("Couldn't Recognize Barcode: "+barcode);
		}
		return title;
	}
	public static ArrayList<ServerProduct> searchProducts(String tags, String category){
		ArrayList<ServerProduct> products = new ArrayList<ServerProduct>();
		//threaded
		//construct the threads to do the request
		List<ProductFetchThread> threads = new ArrayList<ProductFetchThread>();
		for(String source: Configuration.getStoreNameFromCategory(category)){
			threads.add(new ProductFetchThread(source, tags));
		}
		
		//fire all fetching threads
		for(ProductFetchThread thread: threads){
			thread.start();
		}
		
		//wait for all of the threads to finish and add its result to final list
		for(ProductFetchThread thread: threads){
			try {
				thread.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			products.addAll(thread.getProducts());
		}
		
		return products;
	}
	public static ArrayList<ServerProduct> searchOnlineProducts(String tags){
		ArrayList<ServerProduct> products = new ArrayList<ServerProduct>();
		products = new GoogleShoppingRequest(tags).execute();
		return products;
	}
	@Deprecated
	public static ArrayList<ServerProduct> searchProducts(String tags){
		ArrayList<ServerProduct> products = new ArrayList<ServerProduct>();
		//threaded
		//construct the threads to do the request
		List<ProductFetchThread> threads = new ArrayList<ProductFetchThread>();
		for(String source: Configuration.getProviderList()){
			threads.add(new ProductFetchThread(source, tags));
		}
		
		//fire all fetching threads
		for(ProductFetchThread thread: threads){
			thread.start();
		}
		
		//wait for all of the threads to finish and add its result to final list
		for(ProductFetchThread thread: threads){
			try {
				thread.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			products.addAll(thread.getProducts());
		}
		
		return products;
	}
	
	public static ArrayList<ServerProduct> computeSimilarity(String targetFilePath, ArrayList<ServerProduct> products){
		ArrayList<ServerProduct> processedList = new ArrayList<ServerProduct>();
		List<ImageCompareThread> threads = new ArrayList<ImageCompareThread> ();
		int subsize = products.size()/Configuration.NUMBER_OF_IMAGE_THREAD;
		if (subsize==0) subsize=1;
		for(int i = 0; ;i += subsize){
			
			if (i+subsize>products.size()){
				threads.add(new ImageCompareThread(targetFilePath,products.subList(i, products.size())));
				break;
			}
			else{
				threads.add(new ImageCompareThread(targetFilePath, products.subList(i, i+subsize)));
			}
		}
		
		//fire all threads
		for(Thread thread: threads){
			thread.start();
		}
		
		//collect ouput
		for(ImageCompareThread thread: threads){
			try {
				thread.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			processedList.addAll(thread.getProcessedList());
		}
		
		
		//sort and trim the output
		Collections.sort(processedList);
		int endIndex = Configuration.MAX_NUMBER_PRODUCTS;
		if(endIndex>processedList.size()){
			endIndex = processedList.size();
		}
		return new ArrayList<ServerProduct>(processedList.subList(0, endIndex));
		
	}
	
	private static List<ServerProduct>  merge(List<ServerProduct> products){
		List<ServerProduct> mproducts = new ArrayList<ServerProduct>();
		
		//build up the hashmap
		HashMap<String,List<ServerProduct>> map= new HashMap<String,List<ServerProduct>>();
		for(ServerProduct product:products){
			if(map.get(product.getModelNumber()) == null){
				List<ServerProduct> eachMergeProducts = new ArrayList<ServerProduct>();
				eachMergeProducts.add(product);
				map.put(product.getModelNumber(), eachMergeProducts);
			}else{
				map.get(product.getModelNumber()).add(product);
			}
		}
		
		//reconstruct merged list
		for(String key: map.keySet()){
			ServerProduct p = map.get(key).get(0);
			List<ServerStore> eachMergeStores = new ArrayList<ServerStore>();
			for(ServerProduct prd: map.get(key)){
				eachMergeStores.addAll(prd.getStores());
			}
			p.setStores((ArrayList<ServerStore>) eachMergeStores);
			mproducts.add(p);
		}
		
		return mproducts;
	}
	public String test(String tags) {
		String result = "None";
		// JsonFactory jsonFactory = new JsonFactory();
		// HttpTransport transport =new NetHttpTransport();
		// Shopping shopping = new Shopping.Builder(transport,jsonFactory,null)
		// .setGoogleClientRequestInitializer(new
		// ShoppingRequestInitializer(DEV_KEY))
		// .build();
		// try {
		// List productsList = shopping.products().list(tags);
		//
		// //request setting
		// productsList.setCountry(COUNTRY);
		// Products products = productsList.execute();
		// System.out.println(products.getTotalItems());
		// System.out.println(products.getId());
		//
		// } catch (IOException e) {
		// // TODO Auto-generated catch block
		// System.out.println(e.getMessage());
		// }

		return result;
	}

}
